import * as THREE from "../../../../modules/three/three.module.js";

class BoxFrameMesh extends THREE.LineSegments {
  _box = new THREE.Box3()
  _boxMesh

  constructor(color = '#2baeff', useBoxMesh = false) {
    const indices = new Uint16Array([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7])
    const positions = new Float32Array(8 * 3)

    const geometry = new THREE.BufferGeometry()
    geometry.setIndex(new THREE.BufferAttribute(indices, 1))
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))

    super(geometry, new THREE.LineBasicMaterial({color: color, toneMapped: false, depthTest: false, transparent: true}))
    this.renderOrder = 90

    this.type = 'BoxGroupFrame'

    if (useBoxMesh) {
      const cube = new THREE.BoxGeometry(1, 1, 1)
      this._boxMesh = new THREE.Mesh(cube, new THREE.MeshBasicMaterial({transparent: true, opacity: 0, depthTest: false, depthWrite: false}))
      this._boxMesh.scale.set(0.001, 0.001, 0.001)
      this.add(this._boxMesh)
    }
    this.update(new THREE.Box3(new THREE.Vector3(), new THREE.Vector3(10, 10, 10)))
  }

  update(box3) {
    this._box.copy(box3)
    const box = this._box

    if (box.isEmpty()) {
      if (this._boxMesh) {
        this._boxMesh.scale.set(0.001, 0.001, 0.001)
      }
      return
    } else {
      if (this._boxMesh) {
        box.getSize(this._boxMesh.scale);
      }
    }

    const min = box.min
    const max = box.max

    /*
      5____4
    1/___0/|
    | 6__|_7
    2/___3/

    0: max.x, max.y, max.z
    1: min.x, max.y, max.z
    2: min.x, min.y, max.z
    3: max.x, min.y, max.z
    4: max.x, max.y, min.z
    5: min.x, max.y, min.z
    6: min.x, min.y, min.z
    7: max.x, min.y, min.z
    */

    const position = this.geometry.attributes.position
    const array = position.array

    array[0] = max.x; array[1] = max.y; array[2] = max.z
    array[3] = min.x; array[4] = max.y; array[5] = max.z
    array[6] = min.x; array[7] = min.y; array[8] = max.z
    array[9] = max.x; array[10] = min.y; array[11] = max.z
    array[12] = max.x; array[13] = max.y; array[14] = min.z
    array[15] = min.x; array[16] = max.y; array[17] = min.z
    array[18] = min.x; array[19] = min.y; array[20] = min.z
    array[21] = max.x; array[22] = min.y; array[23] = min.z

    position.needsUpdate = true

    this.geometry.computeBoundingSphere()
  }

  /**
   * @param {ModelEntity} modelEntity
   */
  setFromModel(modelEntity) {
    this.modelEntity = modelEntity;
    this.scale.set(1, 1, 1);
    const box3 = new THREE.Box3().setFromObject(modelEntity);
    const size = box3.getSize(new THREE.Vector3());
    const pos = new THREE.Vector3().copy(modelEntity.position);
    pos.z += size.z * 0.5;
    const hx = size.x * 0.5;
    const hy = size.y * 0.5;
    const hz = size.z * 0.5;
    box3.max.set(hx, hy, hz);
    box3.min.set(-hx, -hy, -hz);
    this.update(box3);
    this.position.copy(pos);
  }

  copy(source) {
    THREE.LineSegments.prototype.copy.call(this, source)

    return this
  }
}

export default BoxFrameMesh
